package cn.autumnorange.app.common.rpc.security;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.web.PortResolver;
import org.springframework.security.web.savedrequest.SavedCookie;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.Map.Entry;

public class ConsumerSavedRequestImpl implements ConsumerSavedRequest {
  private static volatile Properties properties ;
  private static volatile YamlPropertiesFactoryBean yamlMapFactoryBean;
  public static final String yml="application-dev.yml";
  static {
    if (yamlMapFactoryBean == null) {

      synchronized (YamlPropertiesFactoryBean.class) {
        if (yamlMapFactoryBean == null) {
          yamlMapFactoryBean = new YamlPropertiesFactoryBean();
          // 可以加载多个yml文件
          yamlMapFactoryBean.setResources(new ClassPathResource(yml));
          // properties存有yml参数
          properties = yamlMapFactoryBean.getObject();
        }
      }
    }
  }
  // 登录获取code地址调整经过网关解决跨域校验

  protected static final Log logger = LogFactory.getLog(ConsumerSavedRequestImpl.class);
  private static final String HEADER_IF_NONE_MATCH = "If-None-Match";
  private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
  private final ArrayList<SavedCookie> cookies;
  private final ArrayList<Locale> locales;
  private final Map<String, List<String>> headers;
  private final Map<String, String[]> parameters;
  private final String contextPath;
  private final String method;
  private final String pathInfo;
  private final String queryString;
  private String requestURI;
  private String requestURL;
  private final String scheme;
  private String serverName;
  private final String servletPath;
  private int serverPort;

  public void setRequestURI(String requestURI) {
    this.requestURI = requestURI;
  }

  public void setRequestURL(String requestURL) {
    this.requestURL = requestURL;
  }

  public void setServerName(String serverName) {
    this.serverName = serverName;
  }

  public void setServerPort(int serverPort) {
    this.serverPort = serverPort;
  }

  public ConsumerSavedRequestImpl(HttpServletRequest request, PortResolver portResolver) {
    this.cookies = new ArrayList();
    this.locales = new ArrayList();
    this.headers = new TreeMap(String.CASE_INSENSITIVE_ORDER);
    this.parameters = new TreeMap();
    Assert.notNull(request, "Request required");
    Assert.notNull(portResolver, "PortResolver required");
    this.addCookies(request.getCookies());
    Enumeration names = request.getHeaderNames();

    while (true) {
      String name;
      do {
        do {
          if (!names.hasMoreElements()) {
            this.addLocales(request.getLocales());
            this.addParameters(request.getParameterMap());
            this.method = request.getMethod();
            this.pathInfo = request.getPathInfo();
            this.queryString = request.getQueryString();
            this.requestURI = request.getRequestURI();
            this.serverPort = portResolver.getServerPort(request);
            this.requestURL = request.getRequestURL().toString();
            this.scheme = request.getScheme();
            this.serverName = request.getServerName();
            this.contextPath = request.getContextPath();
            this.servletPath = request.getServletPath();
            return;
          }

          name = (String) names.nextElement();
        } while ("If-Modified-Since".equalsIgnoreCase(name));
      } while ("If-None-Match".equalsIgnoreCase(name));

      Enumeration values = request.getHeaders(name);

      while (values.hasMoreElements()) {
        this.addHeader(name, (String) values.nextElement());
      }
    }
  }

  private ConsumerSavedRequestImpl(ConsumerSavedRequestImpl.Builder builder) {
    this.cookies = new ArrayList();
    this.locales = new ArrayList();
    this.headers = new TreeMap(String.CASE_INSENSITIVE_ORDER);
    this.parameters = new TreeMap();
    this.contextPath = builder.contextPath;
    this.method = builder.method;
    this.pathInfo = builder.pathInfo;
    this.queryString = builder.queryString;
    this.requestURI = builder.requestURI;
    this.requestURL = builder.requestURL;
    this.scheme = builder.scheme;
    this.serverName = builder.serverName;
    this.servletPath = builder.servletPath;
    this.serverPort = builder.serverPort;
  }

  private void addCookies(Cookie[] cookies) {
    if (cookies != null) {
      Cookie[] var2 = cookies;
      int var3 = cookies.length;

      for (int var4 = 0; var4 < var3; ++var4) {
        Cookie cookie = var2[var4];
        this.addCookie(cookie);
      }
    }
  }

  private void addCookie(Cookie cookie) {
    this.cookies.add(new SavedCookie(cookie));
  }

  private void addHeader(String name, String value) {
    List<String> values = (List) this.headers.get(name);
    if (values == null) {
      values = new ArrayList();
      this.headers.put(name, values);
    }

    ((List) values).add(value);
  }

  private void addLocales(Enumeration<Locale> locales) {
    while (locales.hasMoreElements()) {
      Locale locale = (Locale) locales.nextElement();
      this.addLocale(locale);
    }
  }

  private void addLocale(Locale locale) {
    this.locales.add(locale);
  }

  private void addParameters(Map<String, String[]> parameters) {
    if (!ObjectUtils.isEmpty(parameters)) {
      Iterator var2 = parameters.keySet().iterator();

      while (var2.hasNext()) {
        String paramName = (String) var2.next();
        Object paramValues = parameters.get(paramName);
        if (paramValues instanceof String[]) {
          this.addParameter(paramName, (String[]) ((String[]) paramValues));
        } else if (logger.isWarnEnabled()) {
          logger.warn("ServletRequest.getParameterMap() returned non-String array");
        }
      }
    }
  }

  private void addParameter(String name, String[] values) {
    this.parameters.put(name, values);
  }

  public boolean doesRequestMatch(HttpServletRequest request, PortResolver portResolver) {
    if (!this.propertyEquals("pathInfo", this.pathInfo, request.getPathInfo())) {
      return false;
    } else if (!this.propertyEquals("queryString", this.queryString, request.getQueryString())) {
      return false;
    } else if (!this.propertyEquals("requestURI", this.requestURI, request.getRequestURI())) {
      return false;
    } else if (!"GET".equals(request.getMethod()) && "GET".equals(this.method)) {
      return false;
    } else if (!this.propertyEquals(
        "serverPort", this.serverPort, portResolver.getServerPort(request))) {
      return false;
    } else if (!this.propertyEquals(
        "requestURL", this.requestURL, request.getRequestURL().toString())) {
      return false;
    } else if (!this.propertyEquals("scheme", this.scheme, request.getScheme())) {
      return false;
    } else if (!this.propertyEquals("serverName", this.serverName, request.getServerName())) {
      return false;
    } else {
      return !this.propertyEquals("contextPath", this.contextPath, request.getContextPath())
          ? false
          : this.propertyEquals("servletPath", this.servletPath, request.getServletPath());
    }
  }

  public String getContextPath() {
    return this.contextPath;
  }

  public List<Cookie> getCookies() {
    List<Cookie> cookieList = new ArrayList(this.cookies.size());
    Iterator var2 = this.cookies.iterator();

    while (var2.hasNext()) {
      SavedCookie savedCookie = (SavedCookie) var2.next();
      cookieList.add(savedCookie.getCookie());
    }

    return cookieList;
  }

  public String getRedirectUrl() {
    return UrlUtils.buildFullRequestUrl(
        this.scheme, this.serverName, 80, this.requestURI, this.queryString);
  }

  public Collection<String> getHeaderNames() {
    return this.headers.keySet();
  }

  public List<String> getHeaderValues(String name) {
    List<String> values = (List) this.headers.get(name);
    return values == null ? Collections.emptyList() : values;
  }

  public List<Locale> getLocales() {
    return this.locales;
  }

  public String getMethod() {
    return this.method;
  }

  public Map<String, String[]> getParameterMap() {
    return this.parameters;
  }

  public Collection<String> getParameterNames() {
    return this.parameters.keySet();
  }

  public String[] getParameterValues(String name) {
    return (String[]) this.parameters.get(name);
  }

  public String getPathInfo() {
    return this.pathInfo;
  }

  public String getQueryString() {
    return this.queryString;
  }

  public String getRequestURI() {
    return this.requestURI;
  }

  @Override
  public String getProtocol() {
    return properties.getProperty("protocol");
  }

  @Override
  public String getHost() {
    // 获取yml里的参数
    return properties.getProperty("gateway-server");
  }

  @Override
  public String getGatewayRoteUrl() {
    return properties.getProperty("gatewayRoteUrl");
  }

  public String getRequestURL() {
    return this.requestURL;
  }

  public String getScheme() {
    return this.scheme;
  }

  public String getServerName() {
    return this.serverName;
  }

  public int getServerPort() {
    return this.serverPort;
  }

  public String getServletPath() {
    return this.servletPath;
  }

  private boolean propertyEquals(String log, Object arg1, Object arg2) {
    if (arg1 == null && arg2 == null) {
      if (logger.isDebugEnabled()) {
        logger.debug(log + ": both null (property equals)");
      }

      return true;
    } else if (arg1 != null && arg2 != null) {
      if (arg1.equals(arg2)) {
        if (logger.isDebugEnabled()) {
          logger.debug(log + ": arg1=" + arg1 + "; arg2=" + arg2 + " (property equals)");
        }

        return true;
      } else {
        if (logger.isDebugEnabled()) {
          logger.debug(log + ": arg1=" + arg1 + "; arg2=" + arg2 + " (property not equals)");
        }

        return false;
      }
    } else {
      if (logger.isDebugEnabled()) {
        logger.debug(log + ": arg1=" + arg1 + "; arg2=" + arg2 + " (property not equals)");
      }

      return false;
    }
  }

  public String toString() {
    return "ConsumerSavedRequestImpl[" + this.getRedirectUrl() + "]";
  }

  @JsonIgnoreProperties(ignoreUnknown = true)
  @JsonPOJOBuilder(withPrefix = "set")
  public static class Builder {
    private List<SavedCookie> cookies = null;
    private List<Locale> locales = null;
    private Map<String, List<String>> headers;
    private Map<String, String[]> parameters;
    private String contextPath;
    private String method;
    private String pathInfo;
    private String queryString;
    private String requestURI;
    private String requestURL;
    private String scheme;
    private String serverName;
    private String servletPath;
    private int serverPort;

    public Builder() {
      this.headers = new TreeMap(String.CASE_INSENSITIVE_ORDER);
      this.parameters = new TreeMap();
      this.serverPort = 80;
    }

    public ConsumerSavedRequestImpl.Builder setCookies(List<SavedCookie> cookies) {
      this.cookies = cookies;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setLocales(List<Locale> locales) {
      this.locales = locales;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setHeaders(Map<String, List<String>> header) {
      this.headers.putAll(header);
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setParameters(Map<String, String[]> parameters) {
      this.parameters = parameters;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setContextPath(String contextPath) {
      this.contextPath = contextPath;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setMethod(String method) {
      this.method = method;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setPathInfo(String pathInfo) {
      this.pathInfo = pathInfo;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setQueryString(String queryString) {
      this.queryString = queryString;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setRequestURI(String requestURI) {
      this.requestURI = requestURI;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setRequestURL(String requestURL) {
      this.requestURL = requestURL;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setScheme(String scheme) {
      this.scheme = scheme;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setServerName(String serverName) {
      this.serverName = serverName;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setServletPath(String servletPath) {
      this.servletPath = servletPath;
      return this;
    }

    public ConsumerSavedRequestImpl.Builder setServerPort(int serverPort) {
      this.serverPort = serverPort;
      return this;
    }

    public ConsumerSavedRequestImpl build() {
      ConsumerSavedRequestImpl savedRequest = new ConsumerSavedRequestImpl(this);
      Iterator var2;
      if (!ObjectUtils.isEmpty(this.cookies)) {
        var2 = this.cookies.iterator();

        while (var2.hasNext()) {
          SavedCookie cookie = (SavedCookie) var2.next();
          savedRequest.addCookie(cookie.getCookie());
        }
      }

      if (!ObjectUtils.isEmpty(this.locales)) {
        savedRequest.locales.addAll(this.locales);
      }

      savedRequest.addParameters(this.parameters);
      this.headers.remove("If-Modified-Since");
      this.headers.remove("If-None-Match");
      var2 = this.headers.entrySet().iterator();

      while (var2.hasNext()) {
        Entry<String, List<String>> entry = (Entry) var2.next();
        String headerName = (String) entry.getKey();
        List<String> headerValues = (List) entry.getValue();
        Iterator var6 = headerValues.iterator();

        while (var6.hasNext()) {
          String headerValue = (String) var6.next();
          savedRequest.addHeader(headerName, headerValue);
        }
      }

      return savedRequest;
    }
  }
}
